package cn.hg.solon.plugin.activerecord.demo.common.provider;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import org.noear.solon.Utils;

import com.jfinal.kit.Kv;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.DbKit;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Table;
import com.jfinal.plugin.activerecord.TableMapping;

import cn.hg.solon.plugin.activerecord.demo.common.BaseModel;

/**
 * Generated by Solon.
 */
public abstract class BaseProvider<M extends BaseModel<M>> {

    /**
     * 日志
     */
    protected Logger log = Logger.getLogger(this.getClass().getName());

    /**
     * 数据库访问对象
     */
    protected BaseModel<M> DAO = null;

    /**
     * 数据库名
     */
    protected String _dbName = DbKit.MAIN_CONFIG_NAME;

    /**
     * 名称空间
     */
    protected String namespace = "";

    protected BaseProvider() {
        this._dbName = DbKit.MAIN_CONFIG_NAME;
        this.DAO = this._initDao().use(this._dbName);
    }

    protected BaseProvider(String _dbName, String namespace) {
        this._dbName = _dbName;
        this.namespace = namespace + ".";
        this.DAO = this._initDao().use(this._dbName);
    }

    /**
     * 获取 Model 对应的 Table
     * @return Table 对象
     */
    protected Table _getTable() {
        return TableMapping.me().getTable(this.DAO.getClass());
    }

    /**
     * 初始化 DAO 子类可以复写 自定义自己的 DAO
     *
     * @return Model 对象
     */
    @SuppressWarnings("unchecked")
    protected M _initDao() {
        Class<?> clz = this.getClass();

        if (clz.getName().indexOf("$") > 0) {
            clz = clz.getSuperclass();
        }

        Type type = Utils.loadClass(clz.getName()).getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Class<M> modelClass = (Class<M>)((ParameterizedType)type).getActualTypeArguments()[0];
            try {
                return (M)Utils.newInstance(modelClass, null);
            } catch (Exception e) {

            }
        }

        this.log.warning("Not define Model class in Servce: " + Utils.loadClass(clz.getName()));
        return null;
    }

    /**
     * 统计总记录数
     *
     * @return 记录数
     */
    public long count() {
        return Db.use(this._dbName).queryLong("SELECT COUNT(*) FROM " + this._getTable().getName());
    }

    /**
     * 通过 Model 统计满足条件的记录数
     *
     * @param model Model 对象
     * @return 记录数
     */
    public long countBy(M model) {
        return this.countBy(model != null ? model.toMap() : null);
    }


    /**
     * 通过 Map 统计满足条件的记录数
     *
     * @param map Map 参数表
     * @return 记录数
     */
    public long countBy(Map<String, ?> map) {
        Kv kv = Kv.create();
        if (map != null) {
            kv.set(map);
        }

        return Db.use(this._dbName).template(this.namespace + "countBy", kv).queryLong();
    }


    /**
     * 通过 Model 删除满足条件的记录
     *
     * @param model Model 对象
     * @return 记录数
     */
    public long deleteBy(M model) {
        if (model == null) {
            return 0L;
        }
        return this.deleteBy(model.toMap());
    }


    /**
     * 通过 Map 删除满足条件的记录
     *
     * @param map Map 参数表
     * @return 记录数
     */
    public long deleteBy(Map<String, ?> map) {
        if (map == null || map.size() == 0) {
            return 0L;
        }

        return Db.use(this._dbName).template(this.namespace + "deleteBy", map).update();
    }


    /**
     * 根据 ID 删除记录
     *
     * @param id 记录的 ID
     * @return 是否成功
     */
    public boolean deleteById(Object id) {
        return this.DAO.use(this._dbName).deleteById(id);
    }


    /**
     * 根据多个 ID 批量删除记录
     *
     * @param ids ID 列表
     * @return 是否成功删除任意记录
     */
    public boolean deleteByIds(Object... ids) {
        boolean flag = false;
        if (ids == null) {
            // null
            return flag;
        }

        for (Object obj : ids) {
            if (obj == null) {
                //null
                continue;
            } else if (obj instanceof Collection<?>) {
                // 集合类型
                Collection<?> colls = (Collection<?>)obj;
                flag |= this.deleteByIds(colls.toArray());
            } else if (obj.getClass().isArray()) {
                // 数组类型
                Object[] arrays = (Object[])obj;
                flag |= this.deleteByIds(arrays);
            } else {
                // 对象类型
                flag |= this.deleteById(obj);
            }
        }

        return flag;
    }


    /**
     * 查询所有记录
     * <p>数据量大时请谨慎使用</p>
     *
     * @return Model 对象列表
     */
    public List<M> findAll(){
        return this.DAO.use(this._dbName).findAll();
    }


    /**
     * 通过 Model 查找满足条件的记录列表
     *
     * @param model Model 对象
     * @return Model 对象列表
     */
    public List<M> findBy(M model){
        return this.findBy(model != null ? model.toMap() : null);
    }


    /**
     * 通过 Model 查找满足条件的记录列表
     *
     * @param model Model 对象
     * @param orderColumn 排序列名
     * @param orderDirection 排序方向："asc" 正序，"desc" 倒序。如果为Null则默认为"asc"
     * @return Model 对象列表
     */
    public List<M> findBy(M model, String orderColumn, String orderDirection){
        return this.findBy(model != null ? model.toMap() : null, orderColumn, orderDirection);
    }


    /**
     * 通过 Map 查找满足条件的记录列表
     *
     * @param map Map 参数表
     * @return Model 对象列表
     */
    public List<M> findBy(Map<String, ?> map){
        return this.findBy(map, null, null);
    }


    /**
     * 通过 Map 查找满足条件的记录列表,并按指定条件排序
     *
     * @param map Map 参数表
     * @param orderColumn 排序列名
     * @param orderDirection 排序方向："asc" 正序，"desc" 倒序。如果为Null则默认为"asc"
     * @return Model 对象列表
     */
    public List<M> findBy(Map<String, ?> map, String orderColumn, String orderDirection){
        Kv kv = Kv.create();
        if (map != null) {
            kv.set(map);
        }
        kv.set("orderColumn", orderColumn);
        kv.set("orderDirection", orderDirection);

        return this.DAO.use(this._dbName).template(this.namespace + "findBy", kv).find();
    }


    /**
     * 通过 ID 查找记录
     *
     * @param id 记录的 ID
     * @return Model 对象
     */
    public M findById(Object id) {
        return this.DAO.use(this._dbName).findById(id);
    }


    /**
     * 通过 Model 查找满足条件的单条记录
     *
     * @param model Model 对象
     * @return Model 对象
     */
    public M findFirstBy(M model) {
        if (model == null || model.size() == 0) {
            return null;
        }

        return this.findFirstBy(model.toMap());
    }


    /**
     * 通过 Model 查找满足条件的单条记录
     *
     * @param model Model 对象
     * @param orderColumn 排序列名
     * @param orderDirection 排序方向："asc" 正序，"desc" 倒序。如果为Null则默认为"asc"
     * @return Model 对象
     */
    public M findFirstBy(M model, String orderColumn, String orderDirection) {
        if (model == null || model.size() == 0) {
            return null;
        }

        return this.findFirstBy(model.toMap(), orderColumn, orderDirection);
    }


    /**
     * 根据 Map 查找单条记录
     *
     * @param map Map 参数表
     * @return Model 对象
     */
    public M findFirstBy(Map<String, ?> map) {
        return this.findFirstBy(map, null, null);
    }


    /**
     * 根据 Map 查找单条记录,并按指定条件排序
     *
     * @param map Map 参数表
     * @param orderColumn 排序列名
     * @param orderDirection 排序方向："asc" 正序，"desc" 倒序。如果为Null则默认为"asc"
     * @return Model 对象
     */
    public M findFirstBy(Map<String, ?> map, String orderColumn, String orderDirection) {
        Page<M> page = this.paginateBy(1, 1, map, orderColumn, orderDirection);

        return (page.getList() != null && page.getList().size() == 1) ? page.getList().get(0) : null;
    }


    public BaseModel<M> getDao() {
        return this.DAO;
    }


    /**
     * 分页返回记录
     *
     * @param pageNumber 起始值为1的页号
     * @param pageSize 默认值为10的页大小
     * @return Model 分页对象
     */
    public Page<M> paginate(int pageNumber, int pageSize){
        return this.DAO.use(this._dbName).paginate(pageNumber, pageSize, "SELECT *", "FROM " + this._getTable().getName());
    }


    /**
     * 通过 Model 查找满足条件的分页记录
     *
     * @param pageNumber 起始值为1的页号
     * @param pageSize 默认值为10的页大小
     * @param model Model 对象
     * @return Model 分页对象
     */
    public Page<M> paginateBy(int pageNumber, int pageSize, M model){
        return this.paginateBy(pageNumber, pageSize, model != null ? model.toMap() : null, null, null);
    }


    /**
     * 通过 Model 查找满足条件的分页记录
     *
     * @param pageNumber 起始值为1的页号
     * @param pageSize 默认值为10的页大小
     * @param model Model 对象
     * @param orderColumn 排序列名
     * @param orderDirection 排序方向："asc" 正序，"desc" 倒序。如果为Null则默认为"asc"
     * @return Model 分页对象
     */
    public Page<M> paginateBy(int pageNumber, int pageSize, M model, String orderColumn, String orderDirection){
        return this.paginateBy(pageNumber, pageSize, model != null ? model.toMap() : null, orderColumn, orderDirection);
    }


    /**
     * 通过 Map 查找满足条件的分页记录
     *
     * @param pageNumber 起始值为1的页号
     * @param pageSize 默认值为10的页大小
     * @param map Map 参数表
     * @return Model 分页对象
     */
    public Page<M> paginateBy(int pageNumber, int pageSize, Map<String, ?> map){
        return this.paginateBy(pageNumber, pageSize, map, null, null);
    }


    /**
     * 通过 Map 查找分页记录,并按指定条件排序
     *
     * @param pageNumber 起始值为1的页号
     * @param pageSize 默认值为10的页大小
     * @param map Map 参数表
     * @param orderColumn 排序列名
     * @param orderDirection 排序方向："asc" 正序，"desc" 倒序。如果为Null则默认为"asc"
     * @return Model 分页对象
     */
    public Page<M> paginateBy(int pageNumber, int pageSize, Map<String, ?> map, String orderColumn, String orderDirection){
        Kv kv = Kv.create();
        if (map != null) {
            kv.set(map);
        }

        kv.set("orderColumn", orderColumn);
        kv.set("orderDirection", orderDirection);

        return this.DAO.use(this._dbName).template(this.namespace + "paginateBy", kv).paginate(pageNumber, pageSize);
    }


    /**
     * 保存 Model 记录
     *
     * @param Model 对象
     * @return 是否成功
     */
    public boolean save(M model) {
        if (model == null) {
            return false;
        }

        return model.use(this._dbName).save();
    }


    /**
     * 批量保存 Model 记录
     *
     * @param list Model 对象列表
     * @return 成功数
     */
    public long saveMore(List<M> list) {
        if (list == null || list.size() == 0) {
            return 0L;
        }

        long count = 0L;
        for (M model : list) {
            if (model == null) {
                continue;
            }
            count = count + (model.use(this._dbName).save() ? 1L : 0L);
        }

        return count;
    }


    public void setDbName(String dbName) {
        this._dbName = dbName;
    }


    /**
     * 更新 Model 记录
     *
     * @param Model 对象
     * @return 是否成功
     */
    public boolean update(M model) {
        if (model == null) {
            return false;
        }

        return model.use(this._dbName).update();
    }


    /**
     * 批量更新 Model 记录
     *
     * @param Model 对象列表
     * @return 更新数
     */
    public long updateMore(List<M> list) {
        if (list == null || list.size() == 0) {
            return 0L;
        }

        long count = 0L;
        for (M model : list) {
            if (model == null) {
                continue;
            }
            count = count + (model.use(this._dbName).update() ? 1L : 0L);
        }

        return count;
    }
}
